跳到主要内容

Session 与 Cookie

概述

参考资料 几种保持登录状态的方式

因为 HTTP 是无状态请求,所以需要自己维持状态

一般来说有三种解决方案

Session 机制保持会话

存在的问题

  • 高并发情况下,会占用服务器大量内存
  • 分布式(一个业务分成几个子业务,部署在多个服务器)或者集群(一个业务部署在多个服务器)的时候,session 不能共享。

解决方案

  • 高并发的时候可以将 session 存储到 redis,如果用户长时间没有访问,将 session 存储到 redis,就减少了服务器的压力。
  • 分布式或者集群的时候,先通过 redis 来判断用户状态也可以实现 session 共享.

使用的方法 登录验证后,创建登录凭证(比如:用户id + 登录时间 + 过期时间),将登录凭证进行加密(为了避免暴露信息),加密后写到浏览器的 cookie,以后,每次请求都发送 cookie,服务器根据对应的解密算法对其进行验证(或者将加密过的 cookie 内容存储到数据库,请求服务器的时候,服务器在数据库进行查找)。

存在的问题

  • 每次访问都提交 cookie,增加请求量
  • 其他访问可能需要 cookie(比如说购物车的信息存放在 cookie),浏览器对每个域存储的 cookie 的大小有限制,那么需要控制加密后的凭证。

Token 机制保持会话

使用方法 cookie 和 session 依赖于浏览器,如果客户端不是浏览器,那么需要手动添加 token(和cookie类似,也是登录凭证),将 token 添加到 http header 或者做为参数添加到 url。

存在的问题

  • 每次访问的时候手动添加 token
  • 和 cookie 的方式一样增加了请求量

Cookie 保存在客户端

每次请求服务器都会把 Cookie 也传过去

Cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成 Cookie 的作用范围。

若不设置过期时间: 默认这个 Cookie 的生命周期为浏览器会话期间,关闭访问服务器的浏览器窗口,Cookie 就消失了。一般称为会话Cookie,保存在内存中

若设置了过期时间:则 Cookie 会存储在硬盘上,直到超过有效时间。

Cookie使用例

这里使用 Java 来展示其使用,其他语言都大同小异

注意:下面这个例子

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
boolean flag = false; // 用来判断是否存在某个Cookie

// 先查询是否有这个 Cookie,没有则会返回 null
if (req.getCookies() != null) {
// 已经有 Cookie了则更改其值
for (Cookie cookie : req.getCookies()) { // 遍历数组找到对应的 Cookie

if (cookie.getName().equals("date")) {
System.out.println("读取到了 Cookie " + cookie.getValue());

cookie.setValue(String.valueOf((new Date()).getTime()));
// 设置 Cookie 后直接替换掉原来的就行了
resp.addCookie(cookie);

flag = true; //找到了这个 Cookie
break;
}
}
}

// 找不到或为空则创建 Cookie
if(!flag || req.getCookies() == null){
// 没有则创建一个 Cookie
// Cookie 的 name(key) 不可以重复,如果重复了则会替代
Cookie cookie = new Cookie("date", String.valueOf((new Date()).getTime()));
// 设置 Cookie 的过期时间 24小时
cookie.setMaxAge(60*60*24);
// 同理,删掉 Cookie 设置成 0 就可以了 cookie.setMaxAge(0);
resp.addCookie(cookie);
System.out.println("创建了新的 Cookie");
}
}

Session 原理

Session 保存在服务器端

为什么要用 Session?

因为存在本地的 Cookie 可能会被其他的网站扫描,安全性相对不高,所以需要把一些操作丢到服务器上来执行

Session 的有效时长

服务器会把长时间没有活动的 Session 从服务器内存中清除,此时 Session 便失效。具体根据服务器设置,一般在二三十分钟左右。

实现原理

服务器会为每一个访问服务器的用户创建一个 Session 对象,并且把 Session 对象的 id 保存在本地 Cookie 上,只要用户再次访问服务器时,带着 Session 的 id,服务器就会匹配用户在服务器上的 Session,根据 Session 中的数据,还原用户上次的浏览状态或提供其他人个性化服务。

  • 注意:有些手机不支持 Cookie,所以需要先进行判断设备是否支持 Cookie,如果不支持,则把 id 写进 URL 中

Session使用例

参考资料 艾岩囚心劫--Java中session的用法

这里使用 Java 来展示其使用,其他语言都大同小异

public class SessionDemo1 extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//使用request对象的getSession()获取session,如果session不存在则创建一个
HttpSession session = request.getSession();

//将数据存储到session中
session.setAttribute("date", String.valueOf((new Date()).getTime()));

//获取session的Id
String sessionId = session.getId();

//判断session是不是新创建的
if (session.isNew()) {
response.getWriter().print("session创建成功,session的id是:" + sessionId);
}else {
response.getWriter().print("服务器已经存在该session了,session的id是:" + sessionId);
}
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}